{% extends 'base.html' %}

{% block title %}文档管理 | Tiny QA{% endblock %}

{% block head %}
<style>
.spin {
    animation: spin 1s linear infinite;
}

@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

.progress-bar-animated {
    animation: progress-bar-stripes 1s linear infinite;
}

@keyframes progress-bar-stripes {
    0% { background-position-x: 1rem; }
}
</style>
{% endblock %}

{% block content %}
<div class="container mt-5">
    <h2 class="mb-4">文档管理</h2>
    
    <!-- 当前配置信息 -->
    <div class="alert alert-info">
        <h6><i class="bi bi-info-circle"></i> 当前配置</h6>
        <div class="row">
            <div class="col-md-3">
                <strong>分块策略:</strong> 
                <select id="strategy-select" class="form-select form-select-sm d-inline-block w-auto">
                    <option value="traditional">传统分块</option>
                    <option value="ai_semantic">AI语义分块</option>
                    <option value="ai_topic">AI主题分块</option>
                    <option value="ai_hybrid">AI混合分块</option>
                </select>
            </div>
            <div class="col-md-3">
                <strong>AI模型:</strong> 
                <select id="model-select" class="form-select form-select-sm d-inline-block w-auto">
                    <option value="deepseek-r1:1.5b">DeepSeek 1.5B (快速)</option>
                    <option value="qwen3:4b">Qwen3 4B (中文友好)</option>
                    <option value="llama3.2:latest">Llama3.2 (通用)</option>
                </select>
            </div>
            <div class="col-md-3">
                <strong>块大小:</strong> <span id="chunk-size">加载中...</span>
            </div>
            <div class="col-md-3">
                <strong>块重叠:</strong> <span id="chunk-overlap">加载中...</span>
            </div>
        </div>
        <div class="mt-2">
            <button id="apply-config-btn" class="btn btn-sm btn-primary">
                <i class="bi bi-check-circle"></i> 应用配置
            </button>
            <small class="text-muted ms-2">修改配置后需要重新处理文档</small>
        </div>
    </div>
    
    <!-- 操作按钮 -->
    <div class="mb-3">
        <button id="scan-btn" class="btn btn-primary me-2">
            <i class="bi bi-search"></i> 扫描文档
        </button>
        <button id="process-all-btn" class="btn btn-success me-2">
            <i class="bi bi-gear"></i> 处理所有文档
        </button>
        <button id="reprocess-all-btn" class="btn btn-warning me-2">
            <i class="bi bi-arrow-repeat"></i> 重新处理所有文档
        </button>
        <button id="reset-btn" class="btn btn-danger me-2">
            <i class="bi bi-trash"></i> 重置数据库
        </button>
        <button id="refresh-btn" class="btn btn-secondary">
            <i class="bi bi-arrow-clockwise"></i> 刷新列表
        </button>
    </div>
    
    <!-- 状态消息 -->
    <div id="message" class="alert d-none"></div>
    
    <!-- 进度条 -->
    <div id="progress-container" class="d-none">
        <div class="progress mb-3">
            <div id="progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" 
                 role="progressbar" style="width: 0%">0%</div>
        </div>
        <div id="progress-text" class="text-muted">准备中...</div>
        <div id="progress-details" class="text-muted small"></div>
    </div>
    
    <!-- 文档统计 -->
    <div id="documents-stats">
        <p>正在加载文档统计...</p>
    </div>
    
    <!-- 文档列表 (隐藏) -->
    <div id="documents-list" class="d-none">
        <p>正在加载文档列表...</p>
    </div>
</div>

<script>
// 显示消息
function showMessage(message, type = 'info') {
    const msgDiv = document.getElementById('message');
    msgDiv.className = `alert alert-${type}`;
    msgDiv.textContent = message;
    msgDiv.classList.remove('d-none');
    setTimeout(() => msgDiv.classList.add('d-none'), 5000);
}

// 显示进度条
function showProgress() {
    const progressContainer = document.getElementById('progress-container');
    progressContainer.classList.remove('d-none');
}

// 隐藏进度条
function hideProgress() {
    const progressContainer = document.getElementById('progress-container');
    progressContainer.classList.add('d-none');
}

// 更新进度
function updateProgress(percent, text, details = '') {
    const progressBar = document.getElementById('progress-bar');
    const progressText = document.getElementById('progress-text');
    const progressDetails = document.getElementById('progress-details');
    
    progressBar.style.width = percent + '%';
    progressBar.textContent = Math.round(percent) + '%';
    progressText.textContent = text;
    progressDetails.textContent = details;
}

// 加载文档统计
async function loadDocumentStats() {
    const statsDiv = document.getElementById('documents-stats');
    statsDiv.innerHTML = '<p>正在加载文档统计...</p>';
    
    try {
        const resp = await fetch('/api/documents/stats');
        const data = await resp.json();
        
        let html = `
            <div class="row">
                <div class="col-md-3">
                    <div class="card text-center">
                        <div class="card-body">
                            <i class="bi bi-file-earmark-text text-primary" style="font-size: 2rem;"></i>
                            <h4 class="mt-2">${data.total_files}</h4>
                            <p class="text-muted mb-0">总文件数</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-3">
                    <div class="card text-center">
                        <div class="card-body">
                            <i class="bi bi-file-earmark-pdf text-danger" style="font-size: 2rem;"></i>
                            <h4 class="mt-2">${data.pdf_count}</h4>
                            <p class="text-muted mb-0">PDF文档</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-3">
                    <div class="card text-center">
                        <div class="card-body">
                            <i class="bi bi-file-earmark-word text-primary" style="font-size: 2rem;"></i>
                            <h4 class="mt-2">${data.word_count}</h4>
                            <p class="text-muted mb-0">Word文档</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-3">
                    <div class="card text-center">
                        <div class="card-body">
                            <i class="bi bi-file-earmark-excel text-success" style="font-size: 2rem;"></i>
                            <h4 class="mt-2">${data.excel_count}</h4>
                            <p class="text-muted mb-0">Excel文档</p>
                        </div>
                    </div>
                </div>
            </div>
            
            <div class="row mt-3">
                <div class="col-md-3">
                    <div class="card text-center">
                        <div class="card-body">
                            <i class="bi bi-file-earmark-text text-info" style="font-size: 2rem;"></i>
                            <h4 class="mt-2">${data.txt_count}</h4>
                            <p class="text-muted mb-0">文本文件</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-3">
                    <div class="card text-center">
                        <div class="card-body">
                            <i class="bi bi-file-earmark-text text-warning" style="font-size: 2rem;"></i>
                            <h4 class="mt-2">${data.md_count}</h4>
                            <p class="text-muted mb-0">Markdown</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-3">
                    <div class="card text-center">
                        <div class="card-body">
                            <i class="bi bi-check-circle text-success" style="font-size: 2rem;"></i>
                            <h4 class="mt-2">${data.processed_count}</h4>
                            <p class="text-muted mb-0">已处理</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-3">
                    <div class="card text-center">
                        <div class="card-body">
                            <i class="bi bi-clock text-warning" style="font-size: 2rem;"></i>
                            <h4 class="mt-2">${data.unprocessed_count}</h4>
                            <p class="text-muted mb-0">待处理</p>
                        </div>
                    </div>
                </div>
            </div>
            
            <div class="mt-4">
                <div class="alert alert-info">
                    <i class="bi bi-info-circle me-2"></i>
                    <strong>文档统计说明：</strong>
                    <ul class="mb-0 mt-2">
                        <li>总文件数：文档目录中所有支持格式的文件数量</li>
                        <li>已处理：已完成分块和向量化的文档数量</li>
                        <li>待处理：尚未处理的文档数量</li>
                        <li>点击"扫描文档"可发现新增的文档文件</li>
                    </ul>
                </div>
            </div>
        `;
        
        statsDiv.innerHTML = html;
    } catch (err) {
        statsDiv.innerHTML = '<div class="alert alert-danger">加载统计失败: ' + err.message + '</div>';
    }
}

// 加载文档列表 (保留原有功能，但默认隐藏)
async function loadDocuments() {
    const listDiv = document.getElementById('documents-list');
    listDiv.innerHTML = '<p>正在加载文档列表...</p>';
    
    try {
        const resp = await fetch('/api/documents');
        const data = await resp.json();
        
        if (data.documents && data.documents.length > 0) {
            let html = `
                <div class="table-responsive">
                    <table class="table table-striped table-hover">
                        <thead class="table-dark">
                            <tr>
                                <th>文件名</th>
                                <th>类型</th>
                                <th>大小</th>
                                <th>状态</th>
                                <th>操作</th>
                            </tr>
                        </thead>
                        <tbody>
            `;
            
            for (const doc of data.documents) {
                const sizeKB = (doc.file_size / 1024).toFixed(1);
                const statusBadge = doc.processed ? 
                    '<span class="badge bg-success">已处理</span>' : 
                    '<span class="badge bg-warning">未处理</span>';
                
                html += `
                    <tr>
                        <td>${doc.file_name}</td>
                        <td><span class="badge bg-secondary">${doc.file_type}</span></td>
                        <td>${sizeKB} KB</td>
                        <td>${statusBadge}</td>
                        <td>
                            ${!doc.processed ? `<button class="btn btn-sm btn-outline-primary" onclick="processDocument(${doc.id})">处理</button>` : ''}
                        </td>
                    </tr>
                `;
            }
            
            html += '</tbody></table></div>';
            listDiv.innerHTML = html;
        } else {
            listDiv.innerHTML = `
                <div class="alert alert-info">
                    <h5>暂无文档</h5>
                    <p>点击"扫描文档"按钮来扫描文档目录中的文件。</p>
                </div>
            `;
        }
    } catch (err) {
        listDiv.innerHTML = '<div class="alert alert-danger">加载失败: ' + err.message + '</div>';
    }
}

// 扫描文档
async function scanDocuments() {
    const scanBtn = document.getElementById('scan-btn');
    scanBtn.disabled = true;
    scanBtn.innerHTML = '<i class="bi bi-arrow-clockwise spin"></i> 扫描中...';
    
    try {
        const resp = await fetch('/api/documents/scan', { method: 'POST' });
        const data = await resp.json();
        
        if (resp.ok) {
            showMessage(`扫描完成！发现 ${data.scanned_files.length} 个新文档`, 'success');
            loadDocumentStats(); // 重新加载统计
        } else {
            showMessage('扫描失败: ' + (data.error || '未知错误'), 'danger');
        }
    } catch (err) {
        showMessage('扫描失败: ' + err.message, 'danger');
    } finally {
        scanBtn.disabled = false;
        scanBtn.innerHTML = '<i class="bi bi-search"></i> 扫描文档';
    }
}

// 处理所有文档
async function processAllDocuments() {
    const processBtn = document.getElementById('process-all-btn');
    processBtn.disabled = true;
    processBtn.innerHTML = '<i class="bi bi-arrow-clockwise spin"></i> 处理中...';
    
    // 显示进度条
    showProgress();
    updateProgress(0, '开始处理未处理文档...');
    
    try {
        // 首先获取未处理的文档列表
        const docsResp = await fetch('/api/documents/unprocessed');
        const docsData = await docsResp.json();
        
        if (!docsData.documents || docsData.documents.length === 0) {
            updateProgress(100, '没有未处理的文档');
            setTimeout(() => {
                hideProgress();
                showMessage('没有需要处理的文档', 'info');
            }, 1000);
            return;
        }
        
        const totalDocs = docsData.documents.length;
        let processedDocs = 0;
        
        // 逐个处理文档
        for (const doc of docsData.documents) {
            try {
                const startTime = Date.now();
                updateProgress(
                    (processedDocs / totalDocs) * 100, 
                    `正在处理: ${doc.file_name} (${processedDocs + 1}/${totalDocs})`,
                    `文件大小: ${(doc.file_size / 1024).toFixed(1)} KB`
                );
                
                const resp = await fetch(`/api/documents/${doc.id}/process`, { method: 'POST' });
                const data = await resp.json();
                
                if (resp.ok) {
                    processedDocs++;
                    const endTime = Date.now();
                    const duration = ((endTime - startTime) / 1000).toFixed(1);
                    updateProgress(
                        (processedDocs / totalDocs) * 100, 
                        `已完成: ${doc.file_name} (${processedDocs}/${totalDocs})`,
                        `处理时间: ${duration}秒 | 生成块数: ${data.chunk_count}`
                    );
                } else {
                    console.error(`处理文档 ${doc.file_name} 失败:`, data.error);
                    updateProgress(
                        (processedDocs / totalDocs) * 100, 
                        `处理失败: ${doc.file_name} (${processedDocs + 1}/${totalDocs})`,
                        `错误: ${data.error}`
                    );
                }
                
                // 短暂延迟，让用户看到进度
                await new Promise(resolve => setTimeout(resolve, 300));
                
            } catch (err) {
                console.error(`处理文档 ${doc.file_name} 出错:`, err);
                updateProgress(
                    (processedDocs / totalDocs) * 100, 
                    `处理出错: ${doc.file_name} (${processedDocs + 1}/${totalDocs})`,
                    `错误: ${err.message}`
                );
            }
        }
        
        updateProgress(100, '处理完成！', `成功处理 ${processedDocs}/${totalDocs} 个文档`);
        setTimeout(() => {
            hideProgress();
            showMessage(`批量处理完成！共处理 ${processedDocs} 个文档`, 'success');
            loadDocumentStats(); // 重新加载统计
        }, 1000);
        
    } catch (err) {
        hideProgress();
        showMessage('批量处理失败: ' + err.message, 'danger');
    } finally {
        processBtn.disabled = false;
        processBtn.innerHTML = '<i class="bi bi-gear"></i> 处理所有文档';
    }
}

// 重新处理所有文档
async function reprocessAllDocuments() {
    // 确认对话框
    const confirmed = confirm('⚠️ 警告：重新处理所有文档将删除现有的分块和向量数据，并重新生成。\n\n此操作不可撤销，确定要继续吗？');
    if (!confirmed) {
        return;
    }
    
    const reprocessBtn = document.getElementById('reprocess-all-btn');
    reprocessBtn.disabled = true;
    reprocessBtn.innerHTML = '<i class="bi bi-arrow-clockwise spin"></i> 重新处理中...';
    
    // 显示进度条
    showProgress();
    updateProgress(0, '开始重新处理...');
    
    try {
        // 首先获取所有文档列表
        const docsResp = await fetch('/api/documents');
        const docsData = await docsResp.json();
        
        if (!docsData.documents || docsData.documents.length === 0) {
            updateProgress(100, '没有文档需要处理');
            setTimeout(() => {
                hideProgress();
                showMessage('没有文档需要处理', 'info');
            }, 1000);
            return;
        }
        
        const totalDocs = docsData.documents.length;
        let processedDocs = 0;
        
        // 逐个重新处理文档
        for (const doc of docsData.documents) {
            try {
                const startTime = Date.now();
                updateProgress(
                    (processedDocs / totalDocs) * 100, 
                    `正在重新处理: ${doc.file_name} (${processedDocs + 1}/${totalDocs})`,
                    `重置状态中...`
                );
                
                // 重置文档状态
                await fetch(`/api/documents/${doc.id}/reset`, { method: 'POST' });
                
                updateProgress(
                    (processedDocs / totalDocs) * 100, 
                    `正在重新处理: ${doc.file_name} (${processedDocs + 1}/${totalDocs})`,
                    `文件大小: ${(doc.file_size / 1024).toFixed(1)} KB`
                );
                
                // 重新处理文档
                const resp = await fetch(`/api/documents/${doc.id}/process`, { method: 'POST' });
                const data = await resp.json();
                
                if (resp.ok) {
                    processedDocs++;
                    const endTime = Date.now();
                    const duration = ((endTime - startTime) / 1000).toFixed(1);
                    updateProgress(
                        (processedDocs / totalDocs) * 100, 
                        `已完成: ${doc.file_name} (${processedDocs}/${totalDocs})`,
                        `处理时间: ${duration}秒 | 生成块数: ${data.chunk_count}`
                    );
                } else {
                    console.error(`重新处理文档 ${doc.file_name} 失败:`, data.error);
                    updateProgress(
                        (processedDocs / totalDocs) * 100, 
                        `重新处理失败: ${doc.file_name} (${processedDocs + 1}/${totalDocs})`,
                        `错误: ${data.error}`
                    );
                }
                
                // 短暂延迟，让用户看到进度
                await new Promise(resolve => setTimeout(resolve, 300));
                
            } catch (err) {
                console.error(`重新处理文档 ${doc.file_name} 出错:`, err);
                updateProgress(
                    (processedDocs / totalDocs) * 100, 
                    `重新处理出错: ${doc.file_name} (${processedDocs + 1}/${totalDocs})`,
                    `错误: ${err.message}`
                );
            }
        }
        
        updateProgress(100, '重新处理完成！', `成功处理 ${processedDocs}/${totalDocs} 个文档`);
        setTimeout(() => {
            hideProgress();
            showMessage(`重新处理完成！共处理 ${processedDocs} 个文档`, 'success');
            loadDocumentStats(); // 重新加载统计
        }, 1000);
        
    } catch (err) {
        hideProgress();
        showMessage('重新处理失败: ' + err.message, 'danger');
    } finally {
        reprocessBtn.disabled = false;
        reprocessBtn.innerHTML = '<i class="bi bi-arrow-repeat"></i> 重新处理所有文档';
    }
}

// 处理单个文档
async function processDocument(docId) {
    try {
        const resp = await fetch(`/api/documents/${docId}/process`, { method: 'POST' });
        const data = await resp.json();
        
        if (resp.ok) {
            showMessage(`文档处理成功！生成了 ${data.chunk_count} 个文本块`, 'success');
            loadDocumentStats(); // 重新加载统计
        } else {
            showMessage('文档处理失败: ' + (data.error || '未知错误'), 'danger');
        }
    } catch (err) {
        showMessage('文档处理失败: ' + err.message, 'danger');
    }
}

// 重置数据库
async function resetDatabase() {
    // 确认对话框
    const confirmed = confirm('⚠️ 危险操作：重置数据库将删除所有文档记录、分块数据和向量数据。\n\n此操作不可撤销，确定要继续吗？');
    if (!confirmed) {
        return;
    }
    
    const resetBtn = document.getElementById('reset-btn');
    resetBtn.disabled = true;
    resetBtn.innerHTML = '<i class="bi bi-arrow-clockwise spin"></i> 重置中...';
    
    // 显示进度条
    showProgress();
    updateProgress(0, '开始重置数据库...');
    
    try {
        const resp = await fetch('/api/documents/reset', { method: 'POST' });
        const data = await resp.json();
        
        if (resp.ok) {
            updateProgress(100, '重置完成！');
            setTimeout(() => {
                hideProgress();
                showMessage('数据库重置完成！', 'success');
                loadDocumentStats(); // 重新加载统计
            }, 1000);
        } else {
            hideProgress();
            showMessage('重置失败: ' + (data.error || '未知错误'), 'danger');
        }
    } catch (err) {
        hideProgress();
        showMessage('重置失败: ' + err.message, 'danger');
    } finally {
        resetBtn.disabled = false;
        resetBtn.innerHTML = '<i class="bi bi-trash"></i> 重置数据库';
    }
}

// 事件监听
document.getElementById('scan-btn').addEventListener('click', scanDocuments);
document.getElementById('process-all-btn').addEventListener('click', processAllDocuments);
document.getElementById('reprocess-all-btn').addEventListener('click', reprocessAllDocuments);
document.getElementById('reset-btn').addEventListener('click', resetDatabase);
document.getElementById('refresh-btn').addEventListener('click', loadDocumentStats);
document.getElementById('apply-config-btn').addEventListener('click', applyConfig);

// 加载配置信息
async function loadConfig() {
    try {
        const resp = await fetch('/api/config');
        const data = await resp.json();
        
        // 获取分块策略信息
        const strategyResp = await fetch('/api/chunking-config');
        const strategyData = await strategyResp.json();
        
        // 设置选择器的值
        document.getElementById('strategy-select').value = strategyData.strategy || 'traditional';
        document.getElementById('model-select').value = strategyData.ai_model || 'deepseek-r1:1.5b';
        document.getElementById('chunk-size').textContent = data.chunk_size + ' 字符';
        document.getElementById('chunk-overlap').textContent = data.chunk_overlap + ' 字符';
        
    } catch (err) {
        console.error('加载配置失败:', err);
        document.getElementById('chunk-size').textContent = '加载失败';
        document.getElementById('chunk-overlap').textContent = '加载失败';
    }
}

// 应用配置
async function applyConfig() {
    const strategy = document.getElementById('strategy-select').value;
    const model = document.getElementById('model-select').value;
    
    const applyBtn = document.getElementById('apply-config-btn');
    applyBtn.disabled = true;
    applyBtn.innerHTML = '<i class="bi bi-arrow-clockwise spin"></i> 应用中...';
    
    try {
        const resp = await fetch('/api/chunking-config', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                strategy: strategy,
                ai_model: model
            })
        });
        
        const data = await resp.json();
        
        if (resp.ok) {
            showMessage('配置更新成功！', 'success');
        } else {
            showMessage('配置更新失败: ' + (data.error || '未知错误'), 'danger');
        }
    } catch (err) {
        showMessage('配置更新失败: ' + err.message, 'danger');
    } finally {
        applyBtn.disabled = false;
        applyBtn.innerHTML = '<i class="bi bi-check-circle"></i> 应用配置';
    }
}

// 页面加载时执行
window.onload = function() {
    loadConfig();
    loadDocumentStats();
};
</script>
{% endblock %} 